#pragma once

#include <iostream>
#include <sys/types.h>          
#include <sys/socket.h>
#include <cstdlib>
#include <cstring>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include "ThreadPool.hpp"
#include "Task.hpp"
#include "daemon.hpp"

#include "log.hpp"

extern Log lg;

const int defaultfd = -1;

const std::string defaultip = "0.0.0.0";

const int backlog = 5;  //一般不要设置太大

enum
{
    SocketError = 2,
    BindError,
    ListenError,
    UsageError
};



class TcpSever;

class ThreadData
{
public:
    ThreadData(int fd, const std::string& ip, const uint16_t &port,TcpSever* t)
        :sockfd(fd),clientip(ip),clientport(port),tsvr(t)
        {}
public:
    uint16_t clientport;
    std::string clientip;
    int sockfd;
    TcpSever* tsvr;
};

class TcpSever
{
public:
    TcpSever(const uint16_t &port,const std::string &ip = defaultip):listensockfd_(defaultfd),port_(port),ip_(ip)
    {

    }

    void InitSever()
    {
        listensockfd_ = socket(AF_INET,SOCK_STREAM,0);
        if (listensockfd_ < 0)
        {
            lg(Fatal,"create socket, errno: %d, errstring: %s",errno,strerror(errno));
            exit(SocketError);
        }

        lg(Info,"create socket sucess, sockfd: %d",listensockfd_);

        int opt = 1;
        setsockopt(listensockfd_,SOL_SOCKET,SO_REUSEADDR|SO_REUSEPORT,&opt,sizeof(opt));    //防止偶发性的服务器无法立即重启(tcp协议的时候再说)

        struct sockaddr_in local;
        memset(&local,0,sizeof(local));

        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        inet_aton(ip_.c_str(),&(local.sin_addr));
        //local.sin_addr.s_addr = INADDR_ANY;

        if (bind(listensockfd_,(struct sockaddr*)&local,sizeof(local)) < 0)
        {
            lg(Fatal,"bind error, errno: %d, errstring: %s",errno,strerror(errno));
            exit(BindError);
        }
        lg(Info,"bind socket sucess, listensockfd_: %d",listensockfd_);
        //Tcp是面向连接的, 服务器一般是比较被动的, 服务器一直处于一种, 一直在等待连接到来的状态
        if (listen(listensockfd_,backlog) < 0)
        {
            lg(Fatal,"listen error, errno: %d, errstring: %s",errno,strerror(errno));
            exit(ListenError);
        }
        lg(Info,"listensockfd_ socket sucess, sockfd: %d",listensockfd_);
    }

    // static void* Routine(void* args)
    // {
    //     pthread_detach(pthread_self());

    //     ThreadData* td = static_cast<ThreadData*>(args);


    //     //Service(sockfd,clientip,clinetport);
    //     td->tsvr->Service(td->sockfd,td->clientip,td->clientport);
    //     delete td;

    //     return nullptr;
    // }

    void Start()
    {
        //lg.Enable(Classfile);
        Daemon();
        signal(SIGPIPE,SIG_IGN);
        ThreadPool<Task>::GetInstance()->Start();
        //signal(SIGCHLD,SIG_IGN);
        lg(Info,"tcpServer is running...");
        for (; ;)
        {
            //1. 获取新链接
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(listensockfd_,(sockaddr *)&client,&len);
            if (sockfd < 0)
            {
                lg(Warning,"accept error, errno: %d, errstring: %s",errno,strerror(errno));
                continue;
            }
            //2. 根据新链接通信
            uint16_t clientport = ntohs(client.sin_port);
            char clientip[32] = {0};
            inet_ntop(AF_INET,&(client.sin_addr),clientip,sizeof(clientip));

            lg(Info,"get a new link..., sockfd: %d, client ip: %s, client port: %d\n",sockfd,clientip,clientport);

            //version 1 -- 单进程版
            // Service(sockfd,clientip,clientport);
            // close(sockfd);

            //version 2 -- 多进程版
            // pid_t id = fork();
            // if (id == 0)
            // {
            //     close(listensockfd_);
            //     if (fork() > 0) exit(0); //孙子进程， systeam 领养
            //     //child
            //     Service(sockfd,clientip,clientport);
            //     close(sockfd);
            //     exit(0);
            // }
            // close(sockfd);
            // //father
            // pid_t rid = waitpid(id,nullptr,0);
            // (void)rid; 

            //version 3 -- 多线程版
            // ThreadData* td = new ThreadData(sockfd,clientip,clientport,this);
            // pthread_t tid;
            // pthread_create(&tid,nullptr,Routine,td);

            //version 4 -- 线程池版
            Task t(sockfd,clientip,clientport);
            ThreadPool<Task>::GetInstance()->Push(t);
        }

       
    }

    // void Service(int sockfd,const std::string &clientip, const uint16_t &clientport)
    // {
    //     char  buffer[4096] = {0};
    //     //测试
    //     while (true)
    //     {
    //         size_t n = read(sockfd,buffer,sizeof(buffer));
    //         if (n > 0)
    //         {
    //             buffer[n] = 0;
    //             std::cout << "client say# " << buffer << std::endl;

    //             std::string echo_string = "tcpserver echo#";
    //             echo_string += buffer;

    //             write(sockfd,echo_string.c_str(),echo_string.size());
    //         }
    //         else if (n == 0)
    //         {
    //             lg(Info,"%s:%d quit, server close sockfd: %d",clientip.c_str(),clientport,sockfd);
    //             break;
    //         }
    //         else
    //         {
    //             lg(Warning,"read error, sockfd: %d, client ip: %s, client port: %d\n",sockfd,clientip.c_str(),clientport);
    //             break;
    //         }
    //     }
    // }

    ~TcpSever()
    {}
private:
    int listensockfd_;
    uint16_t port_;
    std::string ip_;
};